/**
 *  @file:      combination_policy.h
 *  @details    Header file for CombinationPolicy class.\n
 *              System: CombEng \n
 *              Language: C++\n
 *
 *  @author     Favio Bettiol
 *  @email      favio.bettiol AT gmail.com
 *
 *  @author     Diego Diaz
 *  @email      diazdiego86 AT gmail.com
 *
 *  @date       August 2010
 *  @version    0.1
 *
 * This file is part of CombEng
 *
 * CombEng : Combinatory Engine, an FuD's abstraction layer for problems that
 * require to combine elements. Also, this layer provides ranking and prune
 * features for these combinations.
 * <http://fud.googlecode.com/>
 *
 * Copyright (C) 2010 - Favio Bettiol and Diego Diaz
 *
 * CombEng is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * CombEng is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with CombEng .  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#ifndef COMBINATION_POLICY_H
#define COMBINATION_POLICY_H

#include <mili/mili.h>
#include <string>
#include "combination_observer.h"

namespace comb_eng
{

/** @brief TODO */
enum StatusType
{
    Success,
    Error
};

/** @brief Represents the status of a combination policy excecution. */
struct Status
{

public:
    /** @brief TODO */
    Status() {}

    /** @brief TODO */
    Status(const std::string& name, const StatusType status)
        : _name(name),
          _status(status)
    {}

    /** @brief TODO */
    inline StatusType get_status() const
    {
        return _status;
    }

    /** @brief TODO */
    inline void set_status(const StatusType& status)
    {
        _status = status;
    }

    /** @brief TODO */
    inline std::string get_name() const
    {
        return _name;
    }

    /** @brief TODO */
    inline void set_name(const std::string& name)
    {
        _name = name;
    }

private:
    /** @brief TODO */
    std::string _name;

    /** @brief TODO */
    StatusType _status;
};


/** @brief Abstract class containing the main features that a combination policy must have. */
template <class T>
class CombinationPolicy
{

public:
    /** @brief Constructor method. */
    CombinationPolicy()
    {}

    /**
     * @brief Constructor method.
     * @param obs  : Observer for the combination policy.
     * @param name : Name for the combination policy.
     */
    CombinationPolicy(CombinationObserver<T>* obs, const std::string& name)
        : _observed_by(obs), _name(name)
    {}

    /** @brief Destructor method. */
    virtual ~CombinationPolicy()
    {}

    /**
     * @brief Attach an observer.
     * @param comb_observer : observer that will pay attention to any change of this combination policy.
     */
    void attach(CombinationObserver<T>* comb_observer)
    {
        _observed_by = comb_observer;
    }

    /**
     * @brief It defines the way of how to combine a set of elements.
     * @param objects_to_combine : set of elements to combine by the combination policy.
     * @param status             : it has the status of execution of combine method (Fail or Success).
     */
    virtual void combine(const std::list<T>&  objects_to_combine, Status& combination_status) = 0;

    /**
    * @brief Returns the name for the combination policy.
    */
    inline std::string get_name()
    {
        return _name;
    }

    /** @brief Returns the combination policy's observer. */
    inline CombinationObserver<T>* get_observed_by()
    {
        return _observed_by;
    }

    virtual CombinationPolicy<T>* clone(CombinationObserver<T>* /*obs*/)
    {
        return NULL;
    }

protected:

    /**
    * @brief Notifies to its observer that a change has occured.
    * @param combination : the new combination generated by the combination policy.
    */
    void notify(const StateSet<T, StateType> & combination)
    {
        std::list <T> comb;
        typename StateSet<T, StateType>::SpecificIterator it = combination.begin_SpecificIterator(comb_eng::Applicable);
        while (! it.end())
        {
            mili::insert_into(comb, it.get_element());
            ++it;
        }
        _observed_by->update(comb);
    }

    /** @brief TODO */
    CombinationObserver<T>* _observed_by;

    /** @brief TODO */
    std::string             _name;
};

}
#endif // COMBINATION_POLICY_H
